# @Version        : 1.0
# @Update Time    : 2024/11/24 17:05
# @File           : task_schema.py
# @IDE            : PyCharm
# @Desc           : 文件描述信息
from enum import StrEnum
from typing import Optional
from pydantic import Field, field_validator
from pydantic_core.core_schema import ValidationInfo
from fastapi_utils.api_model import APIModel

from src.common.enum import JobGroupEnum
from src.common.typing.schema_typing import DatetimeStr, DictStr
from src.schemas.base_schema import MixinSchema
from src.common.typing.validator import datetime_validator
from datetime import datetime
from fastapi import Depends, Query
from src.core.dependencies import QueryParams, Paging
from src.core.query_builder import FilterCriteria, QueryType


class TaskParams(QueryParams):
    def __init__(
        self,
        params: Paging = Depends(Paging),
    ):
        super().__init__(params)


class OperationRecordParam(QueryParams):
    def __init__(
        self,
        username: str = Query(None, description="用户名"),
        summary: str = Query(None, description="描述"),
        method: str = Query(None, description="请求方式"),
        request_id: str = Query(None, description="请求id"),
        params: Paging = Depends(Paging),
    ):
        super().__init__(params)
        self.username = FilterCriteria(QueryType.LIKE, username)
        self.route_name = FilterCriteria(QueryType.LIKE, summary)
        self.method = method
        self.request_id = FilterCriteria(QueryType.LIKE, request_id)


class LoginRecordParam(QueryParams):
    def __init__(
        self,
        username: str = Query(None, description="用户名"),
        start_date: datetime = Query(None, description="开始时间"),
        end_date: datetime = Query(None, description="结束时间"),
        params: Paging = Depends(Paging),
    ):
        super().__init__(params)
        self.username = FilterCriteria(QueryType.LIKE, username)
        self.created_at = FilterCriteria(QueryType.BEFORE_AFTER, (start_date, end_date))


class JobExecStrategy(StrEnum):
    """
    任务执行策略
    """

    interval = "interval"  # 时间间隔
    date = "date"  # 指定日期
    cron = "cron"  # cron 表达式
    once = "once"  # 执行一次，立即执行


class TaskCreate(APIModel):
    """创建任务参数"""

    name: str = Field(..., description="任务名称")
    group: JobGroupEnum = Field(JobGroupEnum.memory, description="任务分组")
    job_class: str = Field(..., description="任务执行实体类")
    job_params: DictStr = Field(
        {}, description="任务执行实体类参数, dict 类型参数, 入参方式为：**kwargs"
    )
    exec_strategy: JobExecStrategy = Field(..., description="执行策略")
    expression: str | None = Field(None, description="执行表达式, 一次任务可以不填")
    is_active: bool = Field(..., description="状态是否正常")
    remark: str | None = Field(None, description="描述")
    start_datetime: DatetimeStr | None = Field(None, description="任务开始时间")
    end_datetime: DatetimeStr | None = Field(None, description="任务结束时间")

    @field_validator("expression")
    def check_expression(cls, v: str, values: ValidationInfo):
        exec_strategy = values.data["exec_strategy"]
        # 判断执行策略类型
        if exec_strategy == JobExecStrategy.cron:
            fields = v.strip().split()
            if len(fields) not in (6, 7):
                raise ValueError("无效的 Cron 表达式")
        elif exec_strategy == JobExecStrategy.interval:
            fields = v.strip().split()
            if len(fields) != 5:
                raise ValueError("无效的 Interval 表达式")
        elif exec_strategy == JobExecStrategy.date:
            return datetime_validator(v)
        return v


class TaskUpdate(TaskCreate):
    id: int = Field(..., description="任务ID")


class TaskActive(APIModel):
    id: int = Field(..., description="任务ID")
    is_active: bool = Field(..., description="状态是否正常", alias="isActive")


class TaskOut(TaskCreate, MixinSchema):
    pass


class HeartbeatInfo(APIModel):
    queue_name: str = Field(..., description="队列名称")
    computer_name: str = Field(..., description="计算机名称")
    computer_ip: str = Field(..., description="计算机IP地址")
    process_id: int = Field(..., description="进程ID")
    consumer_id: int = Field(..., description="消费者ID")
    consumer_uuid: str = Field(..., description="消费者UUID")
    start_datetime_str: DatetimeStr = Field(..., description="开始时间字符串")
    start_timestamp: float = Field(..., description="开始时间戳")
    hearbeat_datetime_str: DatetimeStr = Field(..., description="心跳时间字符串")
    hearbeat_timestamp: float = Field(..., description="心跳时间戳")
    consuming_function: str = Field(..., description="消费函数")
    code_filename: str = Field(..., description="代码文件路径")
    unit_time_for_count: int = Field(..., description="计数单位时间")
    last_x_s_execute_count: int = Field(..., description="过去X秒内的执行次数")
    last_x_s_execute_count_fail: int = Field(..., description="过去X秒内的失败执行次数")
    last_execute_task_time: float = Field(..., description="上次执行任务时间")
    last_x_s_avarage_function_spend_time: float | None = Field(
        None, description="过去X秒内的平均函数耗时"
    )
    msg_num_in_broker: int = Field(..., description="消息队列中的消息数量")
    current_time_for_execute_task_times_every_unit_time: float = Field(
        ..., description="当前单位时间内执行任务的时间"
    )
    last_timestamp_when_has_task_in_queue: float = Field(
        ..., description="队列中有任务时的上次时间戳"
    )
    total_consume_count_from_start: int = Field(
        ..., description="从启动以来的总消费次数"
    )
    total_consume_count_from_start_fail: int = Field(
        ..., description="从启动以来的失败消费次数"
    )
    total_cost_time_from_start: float = Field(..., description="从启动以来的总耗时")
    last_x_s_total_cost_time: float | None = Field(
        None, description="过去X秒内的总耗时"
    )
    avarage_function_spend_time_from_start: float | None = Field(
        None, description="从启动以来的平均函数耗时"
    )


# 队列输出模型
class QueueOut(APIModel):
    queue_name: str = Field(..., description="队列名称")
    broker_kind: str = Field(..., description="broker类型")
    total_avg_time: Optional[float] = Field(None, description="函数累计平均运行时长")
    last_ten_seconds_time: Optional[float] = Field(
        None, description="最近10秒的平均运行时长"
    )
    last_ten_seconds_num: Optional[int] = Field(0, description="最近10秒的运行完成次数")
    last_ten_seconds_fail_num: Optional[float] = Field(
        0, description="最近10秒的运行失败次数"
    )
    consumer_num: Optional[float] = Field(0, description="消费者数量")
    pause_flag: Optional[int] = Field(None, description="是否暂停")
